package com.easy.dev.aop;

import com.easy.dev.entity.Log;
import com.easy.dev.manager.CacheSql;
import com.easy.dev.utils.CollectionUtils;
import com.easy.dev.vo.Result;
import org.apache.tomcat.util.buf.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Aspect
public class AopLoggerAspect {

    private static final Logger logger = LoggerFactory.getLogger(AopLoggerAspect.class);


    HandlerLog handlerLog;

    @Autowired
    private void setHandlerLog(HandlerLog handlerLog) {
        this.handlerLog = handlerLog;
        cacheSqls = new CacheSql<Log>(handlerLog);
    }

    private CacheSql<Log> cacheSqls;

    @Pointcut("execution(public * com.easy.dev.controller.*.*(..))")
    public void pointCut() {

    }

    @Before("pointCut()")
    public void boBefore(JoinPoint joinPoint) {
        //String methodName = joinPoint.getSignature().getName();
        //logger.info("Method Name : [" + methodName + "] ---> AOP before ");
    }

    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint) {
        //String methodName = joinPoint.getSignature().getName();
        //logger.info("Method Name : [" + methodName + "] ---> AOP after ");
    }

    @AfterReturning(pointcut = "pointCut()",returning = "result")
    public void afterReturn(JoinPoint joinPoint, Object result) {
        //String methodName = joinPoint.getSignature().getName();
        //logger.info("Method Name : [" + methodName + "] ---> AOP after return ,and result is : " + result);
    }

    @AfterThrowing(pointcut = "pointCut()",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Method Name : [" + methodName + "] ---> AOP after throwing ,and throwable message is : " + throwable.getMessage());
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Class clazz = joinPoint.getTarget().getClass();
        String className = clazz.getName();
        try {
            logger.info("Class Name : [" + className + "] --- Method Name : [" + methodName + "] ---> AOP around start");
            long startTimeMillis = System.currentTimeMillis();
            //调用 proceed() 方法才会真正的执行实际被代理的方法
            Object result = joinPoint.proceed();
            long execTimeMillis = System.currentTimeMillis() - startTimeMillis;
            logger.info("Method Name : [" + methodName + "] ---> AOP method exec time millis : " + execTimeMillis);
            logger.info("Method Name : [" + methodName + "] ---> AOP around end , and result is : " + result);
            cacheSqls.add(new Log(clazz.getSimpleName(), methodName, null, null, execTimeMillis, StringUtils.join(CollectionUtils.toArray(joinPoint.getArgs())), handlerResult(result),null,0));
            return result;
        } catch (Throwable te) {
            cacheSqls.add(new Log(clazz.getSimpleName(), methodName, null, null, null, StringUtils.join(CollectionUtils.toArray(joinPoint.getArgs())),"",te.getMessage().getBytes(),1));
            logger.error(te.getMessage(),te);
            throw new RuntimeException(te.getMessage());
        }
    }

    /**
     * 处理返回结果过长，只展示重要数据
     * @param result
     * @return
     */
    private String handlerResult(Object result) {
        if (result == null) {
            return "";
        }
        if (result instanceof Result) {
            Result re = (Result) result;
            StringBuilder sb = new StringBuilder();
            sb.append("status=").append(re.getStatus()).append(",msg=").append(re.getMsg());
            Object data = re.getData();
            if (data == null) {
                sb.append(",data=null");
            } else if (data instanceof List) {
                sb.append(",data=List and length=").append(((List)data).size());
            }
            return sb.toString();
        }
        return result.getClass().toString();
    }

}